Repository navigation
Agents: a conversation this agent cannot read fails for good; examples of unique names; no Pydantic AI banner - #303
Conversation
Pydantic AI prints a banner on a process's first agent run unless an installed package started it. A turn starts in a Restate handler, behind the event loop, where it cannot tell, so every server printed it. Turn it off with pydantic_ai.BANNER_ENABLED, as Pydantic AI advises a library that runs agents on its users' behalf.
Restate keeps a key's state, its database with it, when another example is registered: router.py's desk loaded create_agent.py's LangGraph conversation, failed to read it, and was retried for good. The basic agents are openai_assistant, pydantic_ai_assistant, langgraph_assistant and adk_assistant; router.py's desk is front_desk, loop.py's refunds is refund_loop, and create_agent.py's orders service is shipping. A test fails when two examples serve a name; the tutorial's lessons, one application, share theirs.
…ried forever A stored row that the agent's framework cannot load (one stored by an agent of another framework, under the same name) failed the handler with the framework's own error, and Restate retried it for good: every attempt read the same row. Every load of a stored item now goes through load_item, which fails with a terminal error that says so.
There was a problem hiding this comment.
ℹ️ No critical issues — one small suggestion inline.
Reviewed changes
I reviewed all 4 commits: the terminal failure for stored items an agent cannot read, the renamed examples, and the Pydantic AI banner switch.
load_item: wrapsItems.loadand turns any parse failure into aTerminalError. Every formeritems.load(...)call inpython/restate/agents/now goes through it, and a grep finds no direct calls left. Each framework'sloadis a deterministic parse, so a retry could never succeed. Inanswer_once,Conversation.loadruns before anything is written, so the failure leaves no half-stored turn.- Unique example names: across
examples-agents/, each example now serves its own names. The only shared name is the tutorial'swallet, which is intentional.create_agent.py's service no longer collides withsupport.py'sorders, and the curl lines, docstrings andtests/examples_agents.pyall match. pydantic_ai.BANNER_ENABLED = False: the flag exists frompydantic-ai-slim>=2.66.0, the pinned minimum, and_display._banner_suppressedreads it on each call. So setting it at import takes effect.
ℹ️ A framework upgrade that changes the stored format now fails for good too
load_item cannot tell another framework's row apart from a row this agent wrote under an older version of its own framework. Before this PR, a schema change in a pydantic-ai/ADK upgrade kept the invocation retrying, so pinning back or deploying a fix let it recover. Now it fails at once. The error text, which suggests another framework, would also point the wrong way in that case. This is a reasonable trade-off. It is noted here so it is a deliberate choice; a release note might be worth it.
claude-opus-5-5 | 𝕏
…r version of its framework too, and a test From the review of #303: load_item cannot tell another framework's row from one stored by another version of the agent's own framework, so the error says either. A test of the terminal error: an agent of another framework, under the same name, fails for good.
|
On the format change in a framework's upgrade: kept as a terminal error, a deliberate choice. A retrying invocation holds the key, so every message after it waited behind it until a rollback; now a request fails at once, and the stored rows are left as they are, so the next message after a fix is answered. The error now names that case too (da14dce). |
There was a problem hiding this comment.
✅ No new issues found. Both points from the last review are covered.
Reviewed changes
I reviewed the one commit added since the last review (da14dce).
- Broadened the
load_itemerror and docstring: they now name "another version of its framework" as well as another framework. This covers the upgrade case the last review raised, so the message no longer points the wrong way. - Added
test_a_conversation_this_agent_cannot_read_fails_for_good: it stores a turn with the testItems, then reads it with anItemssubclass that rejects those rows, and checks for aTerminalErrorthat carries the originalValueError. The test passes locally.
claude-opus-5-5 | 𝕏

Found by running the agent examples against a real model (OpenAI) and Restate 1.8.1, with one Restate server, as the examples' README suggests.
router.py'sdesk, registered aftercreate_agent.py'sdesk, loadeddesk/alice's LangGraph conversation as Pydantic AI messages: aValidationError, which Restate retried with backoff for good, as every attempt read the same row. Every load of a stored item now goes throughload_item, which fails with a terminal error: "This conversation holds a message that this agent cannot read (stored by an agent of another framework under the same name, or by another version of its framework?): ...". A version of a framework that stores its messages differently now fails a request at once too, rather than retrying it until a rollback: a retrying invocation holds the key, and every message after it waited behind it.tests/agents_conversation.pytests the terminal error (it fails without the fix). Checked live, one framework's conversation read by another's agent: into Pydantic AI or LangGraph,chatandmessagesfail at once, with no invocation left retrying. Into OpenAI, whose items are any JSON, the load succeeds; the provider refuses the foreign messages, and the turn ends refused, as before.openai_assistant,pydantic_ai_assistant,langgraph_assistantandadk_assistant(all four wereassistant);router.py'sdeskisfront_desk,loop.py'srefundsisrefund_loop, andcreate_agent.py'sordersservice isshipping. The tutorial's lessons, one application, keepwallet.restate.agents.pydantic_aisetspydantic_ai.BANNER_ENABLED = False, as Pydantic AI advises a library that runs agents on its users' behalf.Checked with a real model: every agent example but
adk_agent.py(no Gemini key), with the commands its comment lists: tool calls, signals (support,refund_graph,loop), the three-framework team, triage's review, a delayed follow-up; a crash ofsupport.pywhile it waited for an approval resumed with each tool call made once.Checks:
ruff format --check,ruff check, pyright and mypy, andpytest tests/*(561 passed) locally, before the test.